{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "d1f20875-c50d-46df-906b-49ec1d0c6002",
   "metadata": {},
   "source": [
    "# 7.5 使用多层神经网络实现鸢尾花的分类"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "c90a18b9-d8e8-431c-856c-35f1e4ed05e1",
   "metadata": {},
   "source": [
    "### 1.任务描述\n",
    "\n",
    "- 下载鸢尾花数据集\n",
    "- 设计多层神经网络，要求网络具有1个隐含层，隐含层有16个神经元\n",
    "- 训练网络，求解模型\n",
    "- 记录迭代过程中的损失和准确率\n",
    "- 对损失和准确率进行可视化输出"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "f5b4fc39-cbcf-432a-bf1e-e75e642d4b87",
   "metadata": {},
   "source": [
    "### 2.知识准备\n",
    "\n",
    "见教程。\n"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "b624ebee-980f-4c1e-b963-a24ff0b669f6",
   "metadata": {},
   "source": [
    "### 3.任务分析\n",
    "\n",
    "1. 确定网络结构\n",
    "\n",
    "样本的特征数为4，类别数为3，具有1个隐含层，该层神经元数为16。其中的参数矩阵说明如下：\n",
    "\n",
    "- $W_1$：从输入层到隐含层的权值矩阵，形状为(4,16)。\n",
    "- $B_1$：隐含层的阈值，形状为(16,)\n",
    "- $W_2$：从隐含层到输出层的权值矩阵，形状为(16,3)\n",
    "- $B_2$：输出层的阈值，形状为(3,)\n",
    "\n",
    "2. 选择激活函数\n",
    "\n",
    "隐含层：使用ReLU函数\r\n",
    "输出层：由于处理的是多分类问题，所以此处使用Softmax函。\n",
    "\n",
    "4. 选择损失函\n",
    "\n",
    "使用交叉熵损失函数计算损失数"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "435c6090-cfda-4f46-a550-22a368e41e4a",
   "metadata": {},
   "source": [
    "### 4.任务实施\n"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "ec75eb6c-5da3-467d-a471-ca3b47242dd6",
   "metadata": {},
   "source": [
    "执行代码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "2ae9da58-e339-4d22-9f8d-ca255711d89e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 ,训练集准确率: 0.43333334 ,训练集损失: 2.2054243 ,测试集准确率: 0.4 ,测试集损失: 1.721124\n",
      "10 ,训练集准确率: 0.94166666 ,训练集损失: 0.20537521 ,测试集准确率: 0.96666664 ,测试集损失: 0.24966083\n",
      "20 ,训练集准确率: 0.95 ,训练集损失: 0.14952078 ,测试集准确率: 1.0 ,测试集损失: 0.1670941\n",
      "30 ,训练集准确率: 0.9583333 ,训练集损失: 0.12244371 ,测试集准确率: 1.0 ,测试集损失: 0.12479754\n",
      "40 ,训练集准确率: 0.9583333 ,训练集损失: 0.105143175 ,测试集准确率: 1.0 ,测试集损失: 0.09992127\n",
      "50 ,训练集准确率: 0.9583333 ,训练集损失: 0.092960216 ,测试集准确率: 1.0 ,测试集损失: 0.08484709\n"
     ]
    },
    {
     "data": {
      "image/png": "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mBq4iA4n9pBob8KvAyYz3NPaGCtLQADcfrueORKpbqpF4jRhwgS++OIL1q5dS4sWLUosGxwcTFxcXIF9cXFxBAcHF1l+ypQpBbr2JSUlERp6fr9QaWQ9ERGRyrFzJzz2GKxYkbevb1+YNAmu970AHuxIwD338M79AdYFKSJ1kqWJk2EY3H///XzyySesXr2a1q1bl3pOREQE0dHRTJw40blv1apVREREFFney8sLLy8vV4UMKHESERGpDCtXwj/+YdavNpvZRW3SJMir4vubmZWIiAXcrHzz8ePH88477/Dee+9Rv359YmNjiY2NJT093Vlm1KhRTJkyxbn9wAMPsHLlSp5//nn27NnDE088wZYtW5gwYUKVxa3ESUSqk379+hX4Mel8jRkzhmHDhrnseiJl8e675rDYaWnQv785MevHH+dPms7y8NBcICJiCUsTp//9738kJibSr18/QkJCnMvSpUudZY4cOUJMTIxzu0+fPrz33nu88sorhIeH89FHH7F8+fIqmcMplxInERER15k3D/71L3N+xJEjzW567drlK/DII/Dss3DmjFUhiohYmzgZhlHkMmbMGGeZ1atXs/icORpuuukm9u7dS0ZGBrt27WLw4MFVGrcSJxGpLsaMGcOaNWuYP38+NpsNm83G4cOH2bVrF4MGDcLPz4+goCBuu+024uPjned99NFHdO7cGR8fHxo3bkz//v1JTU3liSee4M033+TTTz91Xm/16tXW3aDUaoYBU6bAgw+a2w88YA4GYbfnK7R7Nzz3HDz8MGzdakmcIiJQTQaHqGmUOInUMSXNPeDubk7wVpaybm7g41Ny2XJO0jJ//nz27dtHp06dmDlzJgCenp706tWLO++8k7lz55Kens4jjzzCzTffzHfffUdMTAwjR47kmWeeYfjw4SQnJ/PDDz9gGAaTJk1i9+7dJCUl8cYbbwAlz60nUlHZ2XD33bBokbk9axZMnlzEKHKPPAIOBwwbZo4SISJiESVOFaDESaSO8fMr/tjgwQWH/woMLP7L4fLLIX/rTVgY5GsFAsyf4MshICAAu92Or6+vc3TRp556im7dujFr1ixnuUWLFhEaGsq+fftISUkhOzubG264gVatWgHQuXNnZ1kfHx8yMjKKHa1U5Hzt3WtO6Prll+bvCS+/DHfeWUTBNWvg88/NHyiefrrK4xQRyU+J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Bpw4cQIAX19fbBoytVwcDgcnT57E19cXD4/zS32qReJU3vkyPvzwQ6ZNm8bhw4dp164ds2fPZvDgwVUYsYiI1FaRkZGMHj2anj170qtXL+bNm0dqaqpzlL1Ro0bRvHlzoqKi8Pb2plOngsOXNGjQAKDQfhGRisht7c5NnqT83NzcaNmy5XknnZYnTuWdL2PDhg2MHDmSqKgorrvuOt577z2GDRvGtm3bVEmJiMh5GzFiBCdPnmT69OnExsbStWtXVq5c6Rww4siRI7hplmQRqSI2m42QkBACAwPJysqyOpwayW63u+R722ZY/LRZ7969ueSSS3jppZcAszktNDSU+++/v8j5MkaMGEFqaipffPGFc9/f/vY3unbtysKFC0t9v6SkJAICAkhMTMT//GYYFRGRctJ3cNH0uYiIWKM837+W/mSWO19G//79nftKmy9j48aNBcoDDBw4sMT5NURERERERM6HpV31KjJfRmxsbJHlY2Njiyzv0kkGRURERESkTqr1nbSjoqIICAhwLhrhSEREREREysvSFqfyzpcB5sgi5Sl/7iSDiYmJtGzZUi1PIiIWyP3u1WSOBeV+HqqbRESqVnnqJUsTp/LOlwEQERFBdHQ0EydOdO5btWoVERERRZY/d5LB3A9HLU8iItZJTk4mICDA6jCqjeTkZEB1k4iIVcpSL1k+HHl55ssAeOCBB7j88st5/vnnufbaa1myZAlbtmzhlVdeKdP7NWvWjKNHj1K/fv0KjeWelJREaGgoR48erZMjH+n+df+6/7p7/3D+n4FhGCQnJ9OsWbNKiK7mUt10fnT/un/dv+6/KuolyxOn8s6X0adPH9577z2mTp3Ko48+Srt27Vi+fHmZ53Byc3OjRYsW5x23v79/nfzHmUv3r/vX/dfd+4fz+wzU0lSY6ibX0P3r/nX/uv+KKGu9ZHniBDBhwoRiu+atXr260L6bbrqJm266qZKjEhERERERMdX6UfVERERERETOlxKncvLy8uLxxx8vMOBEXaL71/3r/uvu/YM+g+qqrv930f3r/nX/uv+quH+boTFhRURERERESqQWJxERERERkVIocRIRERERESmFEicREREREZFSKHESEREREREphRKnclqwYAFhYWF4e3vTu3dvfvrpJ6tDqhRr165lyJAhNGvWDJvNxvLlywscNwyD6dOnExISgo+P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",
      "text/plain": [
       "<Figure size 1000x300 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "import matplotlib as mpl\n",
    "import tensorflow as tf\n",
    "\n",
    "# 1，数据获取\n",
    "# 加载训练集\n",
    "TRAIN_URL=\"http://download.tensorflow.org/data/iris_training.csv\"\n",
    "train_path=tf.keras.utils.get_file(TRAIN_URL.split('/')[-1], TRAIN_URL)\n",
    "# 加载测试集\n",
    "TEST_URL=\"http://download.tensorflow.org/data/iris_test.csv\"\n",
    "test_path=tf.keras.utils.get_file(TEST_URL.split('/')[-1],TEST_URL)\n",
    "\n",
    "# 使用Pandas读取数据，得到DataFrame格式数据\n",
    "df_iris_train=pd.read_csv(train_path,header=0)\n",
    "df_iris_test=pd.read_csv(test_path,header=0)\n",
    "# 转换成NumPy格式\n",
    "iris_train=np.array(df_iris_train)\n",
    "iris_test=np.array(df_iris_test)\n",
    "\n",
    "# 2，数据预处理\n",
    "# 2.1，拆分样本特征和标签\n",
    "x_train = iris_train[:,0:4]\n",
    "y_train = iris_train[:,4]\n",
    "# print(x_train.shape,y_train.shape)\n",
    "\n",
    "x_test = iris_test[:,0:4]\n",
    "y_test = iris_test[:,4]\n",
    "# print(x_test.shape,y_test.shape)\n",
    "\n",
    "# 2.2，数据归一化\n",
    "# 由于样本的4个特征值尺度相同，因此不用进行归一化\n",
    "\n",
    "# 2.3，数据中心化\n",
    "# 需要按列中心化，指定axis=0\n",
    "x_train=x_train-np.mean(x_train,axis=0)\n",
    "x_test=x_test-np.mean(x_test,axis=0)\n",
    "# print(x_train)\n",
    "# print(x_test)\n",
    "\n",
    "# 2.4，类型转换\n",
    "# 将训练集特征转为float32类型\n",
    "X_train=tf.cast(x_train,tf.float32)\n",
    "# 将训练集标签转为int32，再转为独热编码\n",
    "Y_train=tf.one_hot(tf.constant(y_train,tf.int32),3)\n",
    "# print(Y_train[0:4,:])\n",
    "# 将测试集特征转为float32类型\n",
    "X_test=tf.cast(x_test,tf.float32)\n",
    "# 将测试集标签转为int32，再转为独热编码\n",
    "Y_test=tf.one_hot(tf.constant(y_test,tf.int32),3)\n",
    "\n",
    "# 3，设置超参数\n",
    "# 学习率\n",
    "learn_rate=0.5\n",
    "# 迭代次数\n",
    "iter=50\n",
    "# 显示频率\n",
    "display_step=10\n",
    "# 模型参数\n",
    "np.random.seed(612)\n",
    "W1=tf.Variable(np.random.randn(4,16),dtype=tf.float32)\n",
    "B1=tf.Variable(np.zeros([16]),dtype=tf.float32)\n",
    "W2=tf.Variable(np.random.randn(16,3),dtype=tf.float32)\n",
    "B2=tf.Variable(np.zeros([3]),dtype=tf.float32)\n",
    "\n",
    "# 4，训练模型\n",
    "# 训练准确率\n",
    "acc_train=[]\n",
    "# 测试准确率\n",
    "acc_test=[]\n",
    "# 训练损失\n",
    "cce_train=[]\n",
    "# 测试损失\n",
    "cce_test=[]\n",
    "\n",
    "for i in range(0,iter+1):\n",
    "    with tf.GradientTape() as tape:\n",
    "        # 训练集隐含层线性结果\n",
    "        hidden_train = tf.matmul(X_train,W1)+B1\n",
    "        # 训练集隐含层输出\n",
    "        Hidden_train=tf.nn.relu(hidden_train)\n",
    "        # 训练集输出层线性结果\n",
    "        pred_train = tf.matmul(Hidden_train,W2)+B2\n",
    "        # 训练集输出层输出\n",
    "        PRED_train=tf.nn.softmax(pred_train)\n",
    "        # 训练集交叉熵损失\n",
    "        Loss_train=tf.reduce_mean(tf.keras.metrics.categorical_crossentropy\n",
    "(y_true=Y_train,y_pred=PRED_train))\n",
    "        \n",
    "    # 测试集隐含层线性输出\n",
    "    Hidden_test=tf.nn.relu(tf.matmul(X_test,W1)+B1)\n",
    "    # 测试集概率输出\n",
    "    PRED_test=tf.nn.softmax(tf.matmul(Hidden_test,W2)+B2)\n",
    "    # 测试集交叉熵损失\n",
    "    Loss_test=tf.reduce_mean(tf.keras.metrics.categorical_crossentropy\n",
    "(y_true=Y_test,y_pred=PRED_test))\n",
    "    \n",
    "    # 将交叉熵损失添加到列表\n",
    "    cce_train.append(Loss_train)\n",
    "    cce_test.append(Loss_test)\n",
    "    # 计算准确率\n",
    "    accuracy_train=tf.reduce_mean(tf.cast(tf.equal(tf.argmax(PRED_train.\n",
    "numpy(),1),y_train),tf.float32))\n",
    "    accuracy_test=tf.reduce_mean(tf.cast(tf.equal(tf.argmax(PRED_test.\n",
    "numpy(),1),y_test),tf.float32))\n",
    "    # 将准确率添加到数组\n",
    "    acc_train.append(accuracy_train)\n",
    "    acc_test.append(accuracy_test)\n",
    "    # 计算偏导数\n",
    "    grads = tape.gradient(Loss_train,[W1,B1,W2,B2])\n",
    "    # 更新参数\n",
    "    W1.assign_sub(learn_rate*grads[0])\n",
    "    B1.assign_sub(learn_rate*grads[1])\n",
    "    W2.assign_sub(learn_rate*grads[2])\n",
    "    B2.assign_sub(learn_rate*grads[3])\n",
    "    if i % display_step==0:\n",
    "        print(i,',训练集准确率:',accuracy_train.numpy(),',训练集损失:',Loss_train.numpy(),',测试集准确率:',accuracy_test.numpy(),',测试集损失:',Loss_test.numpy())\n",
    "        \n",
    "# 5，可视化结果\n",
    "plt.figure(figsize=(10,3))\n",
    "# 5.1，绘制损失\n",
    "plt.subplot(121)\n",
    "# 绘制训练集损失\n",
    "plt.plot(cce_train,color=\"blue\",label=\"train\")\n",
    "# 绘制测试集损失\n",
    "plt.plot(cce_test,'--',color=\"red\",label=\"test\")\n",
    "plt.xlabel(\"Iter\")\n",
    "plt.ylabel(\"cce\")\n",
    "plt.legend([\"train\",\"test\"])\n",
    "\n",
    "# 5.2，绘制准确率\n",
    "plt.subplot(122)\n",
    "# 绘制训练集准确率\n",
    "plt.plot(acc_train,color=\"blue\",label=\"train\")\n",
    "# 绘制测试集准确率\n",
    "plt.plot(acc_test,'--',color=\"red\",label=\"test\")\n",
    "plt.xlabel(\"Iter\")\n",
    "plt.ylabel(\"acc\")\n",
    "plt.legend([\"train\",\"test\"])\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e3b3e36e-8418-4caf-af51-d8ac80e2a321",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
